using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Serialization;

namespace AppEventUtils
{
    public class OrderingTypes
    {
        public const float default_level = 0f;
    
        public const float first_level = -1f;
        public const float second_level = 1f;

        public float add_decimal(float level_value, float decimal_value)
        {
            return level_value + decimal_value;
        }
    }
    public class IdGenerator
    {
        private int _id;

        public IdGenerator()
        {
            _id = 0;
        }

        public int GetNextId()
        {
            _id += 1;
            return _id;
        }
    }

    public class RoomIdGenerators
    {
        private readonly Dictionary<int, IdGenerator> _roomIdGenerators;

        public RoomIdGenerators()
        {
            _roomIdGenerators = new Dictionary<int, IdGenerator>();
        }

        private IdGenerator GetRoomIdGenerator(int roomId)
        {
            if (!_roomIdGenerators.ContainsKey(roomId))
            {
                _roomIdGenerators[roomId] = new IdGenerator();
            }

            return _roomIdGenerators[roomId];
        }

        public int GetNextRoomId(int roomId)
        {
            return GetRoomIdGenerator(roomId).GetNextId();
        }
    }
    
    public class OrderedEventBase : IComparable<OrderedEventBase>
    {
        public bool RemoveWhenRunOnce;
        public event EventHandler<EventArgs> OnEventTriggered;
        // public event EventHandler<string> OnEventTriggered;
        // public event EventHandler<MyEventArgs> OnEventTriggered;
        
        // public delegate void DelegateEventListener(string err);
        public bool active { get; set; } = true;
        public int RoomId { get; private set; }
        public int EventId { get; private set; }

        public float wait_time { get; set; } = 0.1f;
        public float force_wait_time { get; set; } = 0f;
        public float max_running_time { get; set; } = 5f;
        public float min_running_time { get; set; } = 0f;
        public bool block { get; set; } = true;
        public bool finished { get; set; } = false;
        
        public string EventName { get; set; }
        public string msg;
        
        [FormerlySerializedAs("EventKey")] public string EventType;
        public double Ordering { get; set; }
        public DateTime CreateTime { get; private set; }

        private object _EventData;

        public bool auto_convert = true;
        public object EventData
        {
            get
            {
                return _EventData;
            }
            set
            {
                _EventData = value;
                
                // if (!auto_convert)
                //     _EventData = value;
                // else
                // {
                //     
                //     if (BdUtils.is_string(value))
                //     {
                //         _EventData = value;
                //     }
                //     else if (BdUtils.is_dict(value))
                //     {
                //         _EventData = BdUtils.conv_obj_to_json(value);
                //     }
                //     else
                //     {
                //         // raise error
                //         throw new ArgumentException("Invalid type for EventData. Expected a string or dictionary.");
                //     }
                // }
            }
        }

        private static RoomIdGenerators _roomIdGenerators = new RoomIdGenerators();

        // private EventManager.EventCallback event_callback;
        public delegate string EventCallback(object sender, EventArgs args);

        public EventCallback event_callback;
        
        public OrderedEventBase(
            int roomId = 0,
            string eventName = null,
            string eventType=null,
            double ordering = OrderingTypes.default_level,
            object eventData = null,
            bool removeWhenRunOnce = true,
            int? eventId = null,
            EventHandler<EventArgs> event_instance = null,
            EventCallback event_callback = null
            )
        {
            RoomId = roomId;
            EventId = eventId ?? _roomIdGenerators.GetNextRoomId(roomId);
            EventData = eventData;
            EventType = eventType;
            CreateTime = DateTime.UtcNow;
            Ordering = ordering;
            RemoveWhenRunOnce = removeWhenRunOnce;
            EventName = eventName ?? $"{GetType().Name}_{EventId}";

            if (event_instance != null)
                this.OnEventTriggered += event_instance;
            
            this.event_callback = event_callback;
        }

        public int CompareTo(OrderedEventBase other)
        {
            if (RoomId != other.RoomId)
            {
                throw new InvalidOperationException("Events in different rooms cannot be compared!");
            }

            var orderComparison = Ordering.CompareTo(other.Ordering);
            return orderComparison != 0 ? orderComparison : EventId.CompareTo(other.EventId);
        }

        public override string ToString()
        {
            return
                $"{GetType().Name}(EventId={EventId}, EventName='{EventName}', EventType='{EventType}', ordering={Ordering})";
        }

        public string Run(string msg = null)
        {
            this.msg = msg;
            
            OnEventTriggered?.Invoke(this, null);
            
            var res = event_callback?.Invoke(this, null);
            
            // if (RemoveWhenRunOnce)
            //     finished = true;
            
            return res;
        }
    }

    public class OrderedEventList
    {
        public int RoomId { get; private set; }
        public List<OrderedEventBase> Events { get; set; }

        public int Count
        {
            get
            {
                return Events.Count;
            }
        }

        public OrderedEventList(int roomId = 0)
        {
            RoomId = roomId;
            Events = new List<OrderedEventBase>();
        }

        public void AddEvent(OrderedEventBase eventItem)
        {
            var index = Events.BinarySearch(eventItem);
            if (index < 0) index = ~index;
            Events.Insert(index, eventItem);
        }

        public bool RemoveEvent(OrderedEventBase eventItem)
        {
            return Events.Remove(eventItem);
        }

        public bool ContainsEvent(OrderedEventBase eventItem)
        {
            return Events.Contains(eventItem);
        }
        
        public bool HasEvent(OrderedEventBase eventItem)
        {
            return ContainsEvent(eventItem);
        }

        public bool RemoveEventById(int eventId)
        {
            var eventItem = GetEventById(eventId);
            if (eventItem != null)
            {
                Events.Remove(eventItem);
                return true;
            }

            return false;
        }

        public OrderedEventBase GetEventById(int eventId)
        {
            return Events.Find(e => e.EventId == eventId);
        }

        public List<OrderedEventBase> GetEvents()
        {
            return new List<OrderedEventBase>(Events);
        }

        public OrderedEventBase PopNextEvent()
        {
            if (Events.Count > 0)
            {
                var nextEvent = Events[0];
                Events.RemoveAt(0);
                return nextEvent;
            }

            return null;
        }

        public void RunAllEvents(string msg = null)
        {
            foreach (var eventItem in Events.ToList())
            {
                if (!eventItem.active)
                    continue;
                
                eventItem.Run(msg);
                
                if (eventItem.RemoveWhenRunOnce)
                {
                    RemoveEventById(eventItem.EventId);    
                }
            }
        }
    }

    public class MyClient
    {
        // 定义一个方法，模拟错误发生时触发事件
        static void OnErrorOccured(string errorMessage)
        {
            BdPackage.BdUtils.log($"Error handled: {errorMessage}");
        }
        // 定义另一个方法，记录错误日志
        static void LogError(string errorMessage)
        {
            BdPackage.BdUtils.log($"Logging error: {errorMessage}");
        }
        
        // public static void InstanceHandler(object sender, EventArgs args)
        public static void InstanceHandler(object sender, EventArgs args)
        {
            
            // BdPackage.BdUtils.log("Event triggered! Instance method executed.");
            var my_event = (OrderedEventBase)sender;
            BdPackage.BdUtils.log("InstanceHandler --- ", sender, " --- sender.EventData:", my_event.EventData);
        }
        
        public static void run()
        {
            int roomId = 0;
            var eventList = new OrderedEventList(roomId);
    
            for (int i = 0; i < 5; i++)
            {
                var e = new OrderedEventBase(roomId, ordering: (3 + i) % 5, eventData: $"data_{i}");
                eventList.AddEvent(e);
            }

            // var eventData = "hello eventData!";
            var _eventData = new Dictionary<string, object>()
            {
                { "a", 123 },
                { "b", "bbb" },
                { "c", "ccc" },
            };
            var eventData = BdUtils.conv_obj_to_json(_eventData);
            // BdUtils.conv_json_to_dict(eventData);
            
            // var additionalEvent = new OrderedEventBase(roomId, $"OrderedEventBase_{6}", -1, eventData: "data --- hello world!");
            var additionalEvent = new OrderedEventBase(
                roomId: roomId,
                eventName: $"OrderedEventBase_{6}",
                ordering: -1,
                eventData: eventData,
                event_instance: InstanceHandler);

            eventList.AddEvent(additionalEvent);
    
            eventList.RunAllEvents();
            
            // additionalEvent.DelegateEventListener += OnErrorOccured;
            // additionalEvent.OnEventTriggered += OnErrorOccured;
            // additionalEvent.Ordering = 1;
            
            // additionalEvent.OnEventTriggered += InstanceHandler;

            // 绑定事件处理程序
            // additionalEvent.OnEventTriggered += (sender, args) =>
            // {
            //     
            //     BdPackage.BdUtils.log("Event triggered! Handler executed.");
            // };
            
            // 触发事件
            additionalEvent.Run();
        }
    }
}